/*
 * <p>Title: :XmlMetadata.java </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2009</p>
 * <p>Company: Digitalchina Co.Ltd</p>
 * @author lijun
 * @version 1.0
 */
package com.dc.trans.steps.bwzh.metadata.impls;

import java.io.InputStream;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.jdom.input.DOMBuilder;
import org.jdom.output.XMLOutputter;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.dc.trans.steps.bwzh.metadata.interfaces.IMetadata;
import com.dc.trans.steps.bwzh.metadata.interfaces.IMetadataChild;
import com.dc.trans.steps.bwzh.metadata.interfaces.IMetadataContainer;

public class XmlMetadata {

	private IMetadata setMetadataProperties(IMetadata metadata, Element ele) {
		NamedNodeMap pList = ele.getAttributes();
		int attributelength = pList.getLength();
		if (attributelength > 0) {
			for (int i = 0; i < attributelength; i++) {
				Node node = pList.item(i);
				metadata.setProperty(node.getNodeName(), node.getNodeValue());

			}
		}
		return metadata;
	}

	/**
	 * 
	 * @param ele
	 * 
	 * @return
	 */
	private void xmlToMetadata(Element ele, IMetadataContainer metadata) {
		if (!ele.getNodeName().equalsIgnoreCase("#text")) {
			NodeList list = ele.getChildNodes();
			if (list.getLength() > 0) {
				setMetadataProperties(metadata, ele);
				metadata.setDataLable(ele.getNodeName());

				for (int i = 0; i < list.getLength(); i++) {
					Node node = list.item(i);
					String childtype = node.getNodeName();
					
					if (!node.getNodeName().equalsIgnoreCase("#text")) {
						Element ele1 = (Element) list.item(i);
						if (ele1.getChildNodes().getLength() > 0) {
							IMetadataContainer metadataC = createContainerNode(ele1);
							xmlToMetadata(ele1, metadataC, childtype);
							metadataC.setParent(metadata);							
							metadataC.setDataLable(ele1.getNodeName());							
							metadata.addChild(metadataC);
						} else {
							IMetadataChild meta = createChildNode(ele1);
							setMetadataProperties(meta, ele1);
							meta.setParent(metadata);
							meta.setProperty("metadatatype", childtype);
							meta.setDataLable(ele1.getNodeName());
							metadata.addChild(meta);
						}
					}
				}
			} else {
				IMetadataChild meta = createChildNode(ele);
				setMetadataProperties(meta, ele);
				meta.setParent(metadata);
				meta.setDataLable(ele.getNodeName());
				metadata.addChild(meta);
			}
		}

	}

	public IMetadata xmlToMetadata(InputStream in, IMetadataContainer metadata,
			String type) throws Exception {

		DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
		factory.setIgnoringComments(true);
		factory.setIgnoringElementContentWhitespace(true);
		DocumentBuilder build = factory
				.newDocumentBuilder();
		Document doc = build.parse(in);
		NodeList nodeL = doc.getChildNodes();
		for (int i = 0; i < nodeL.getLength(); i++) {
			Node node = nodeL.item(i);
			xmlToMetadata((Element) node, metadata, type);
		}

		return metadata;
	}

	public IMetadata xmlToMetadata(InputStream in, IMetadataContainer metadata)
			throws Exception {
		DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
		factory.setIgnoringComments(true);
		factory.setIgnoringElementContentWhitespace(true);
		DocumentBuilder build = factory
				.newDocumentBuilder();
		Document doc = build.parse(in);
		NodeList nodeL = doc.getChildNodes();
		for (int i = 0; i < nodeL.getLength(); i++) {
			Node node = nodeL.item(i);
			xmlToMetadata((Element) node, metadata);
		}

		return metadata;
	}

	private void xmlToMetadata(Element ele, IMetadataContainer metadata,
			String childType) {

		if (!ele.getNodeName().equalsIgnoreCase("#text")) {
			NodeList list = ele.getChildNodes();
			if (list.getLength() > 0) {
				setMetadataProperties(metadata, ele);
				metadata.setDataLable(ele.getNodeName());
				metadata.setProperty("metadatatype", childType);
				for (int i = 0; i < list.getLength(); i++) {
					Node node = list.item(i);
					// getTextContent
					node.getTextContent();
					
//					if (!node.getNodeName().equalsIgnoreCase("#text")) {
//						Element ele1 = (Element) list.item(i);
//						if (ele1.getChildNodes().getLength() > 0) {
//							IMetadataContainer metadataC = createContainerNode(ele1);
//							xmlToMetadata(ele1, metadataC, childType);
//							metadataC.setParent(metadata);
//							metadataC.setProperty("metadatatype", childType);
//							metadataC.setDataLable(ele1.getNodeName());
//							
//							metadata.addChild(metadataC);
//						} else {
//							IMetadataChild meta = createChildNode(ele1);
//							setMetadataProperties(meta, ele1);
//							meta.setParent(metadata);
//							meta.setProperty("metadatatype", childType);
//							meta.setDataLable(ele1.getNodeName());
//							metadata.addChild(meta);
//						}
//					}
//					else
//						metadata.setProperty("value", node.getTextContent());
					
					if (node.getNodeName().equalsIgnoreCase("#text")) {
						metadata.setProperty("value", node.getTextContent());						
					}
					else if(list.item(i) instanceof Element)
					{						
						Element ele1 = (Element) list.item(i);
						if (ele1.getChildNodes().getLength() > 0) {
							IMetadataContainer metadataC = createContainerNode(ele1);
							xmlToMetadata(ele1, metadataC, childType);
							metadataC.setParent(metadata);
							metadataC.setProperty("metadatatype", childType);
							metadataC.setDataLable(ele1.getNodeName());
							
							metadata.addChild(metadataC);
						} else {
							IMetadataChild meta = createChildNode(ele1);
							setMetadataProperties(meta, ele1);
							meta.setParent(metadata);
							meta.setProperty("metadatatype", childType);
							meta.setDataLable(ele1.getNodeName());
							metadata.addChild(meta);
						}
					}
						
				}
			} else {
				IMetadataChild meta = createChildNode(ele);
				setMetadataProperties(meta, ele);
				meta.setParent(metadata);
				meta.setDataLable(ele.getNodeName());
				metadata.addChild(meta);
			}
		}

	}

	private void setXMLProperties(Element ele, IMetadata metadata) {
		String[] key = metadata.getPropertyNames();
		if (key != null) {
			for (int i = 0; i < key.length; i++) {
				ele.setAttribute(key[i], metadata.getProperty(key[i]));
			}
		}
	}

	public void metadataToXML(Object object, Element ele, Document doc) {

		if (object instanceof IMetadataContainer) {
			IMetadataContainer contaniner = (IMetadataContainer) object;
			setXMLProperties(ele, contaniner);
			List list = contaniner.getChild();
			for (int i = 0; i < list.size(); i++) {
				Object obj = list.get(i);
				Element eleC = null;
				if (obj instanceof IMetadataContainer) {
					IMetadataContainer contaniner1 = (IMetadataContainer) obj;
					eleC = doc.createElement(contaniner1.getDataLable());
					setXMLProperties(eleC, contaniner1);
					metadataToXML(contaniner1, eleC, doc);

				} else if (object instanceof IMetadataChild) {
					IMetadataChild metadataC = (IMetadataChild) obj;
					eleC = doc.createElement(metadataC.getDataLable());
					setXMLProperties(eleC, metadataC);
				}
				ele.appendChild(eleC);
			}

		} else if (object instanceof IMetadataChild) {
			IMetadataChild metadataC = (IMetadataChild) object;
			Element eleC = doc.createElement(metadataC.getDataLable());
			setXMLProperties(eleC, metadataC);
			doc.appendChild(eleC);
		}

	}

	public String getXml(IMetadataContainer metadataContainer) {
		DocumentBuilderFactory build = DocumentBuilderFactory.newInstance();
		build.setIgnoringComments(true);
		build.setIgnoringElementContentWhitespace(true);
		Document doc = null;
		try {
			DocumentBuilder builder = build.newDocumentBuilder();
			doc = builder.newDocument();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		Element root = doc.createElement(metadataContainer.getDataLable());
		metadataToXML(metadataContainer, root, doc);
		doc.appendChild(root);
		return toWriter(doc);

	}

	private String toWriter(Document document) {
		DOMBuilder builder = new DOMBuilder();
		XMLOutputter xml = new XMLOutputter();
		return xml.outputString(builder.build(document));
	}

	protected IMetadataChild createChildNode(Element el) {
		return new MetadataChild();
	}

	protected IMetadataContainer createContainerNode(Element el) {
		return new MetadataContainer();
	}
}
